package ar.edu.unlu.sistemas.ws;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;
import javax.jws.WebMethod;
import javax.jws.WebParam;
import javax.jws.WebService;
import javax.servlet.http.HttpServletRequest;
import javax.xml.ws.WebServiceContext;
import javax.xml.ws.handler.MessageContext;

import org.apache.log4j.Logger;

import ar.edu.unlu.sistemas.ws.business.CORI;
import ar.edu.unlu.sistemas.ws.business.Deserializer;
import ar.edu.unlu.sistemas.ws.business.IndexManager;
import ar.edu.unlu.sistemas.ws.business.PeerManager;
import ar.edu.unlu.sistemas.ws.business.PeerWS;
import ar.edu.unlu.sistemas.ws.business.QueryPropagator;
import ar.edu.unlu.sistemas.ws.business.QueryResultVO;
import ar.edu.unlu.sistemas.ws.business.ResourceDescriptionWS;
import ar.edu.unlu.sistemas.ws.business.ResultsWS;
import ar.edu.unlu.sistemas.ws.business.CORI.ResourceRank;

@WebService(targetNamespace = "http://ws.sistemas.unlu.edu.ar/", endpointInterface = "ar.edu.unlu.sistemas.ws.MovirdroidWebService", portName = "MovirdroidWebServiceImplPort", serviceName = "MovirdroidWebServiceImplService")
public class MovirdroidWebServiceImpl implements MovirdroidWebService {
	
	private static Logger logger = Logger.getLogger("web-service");
	private static Integer messagesCounter = 0;
	
	@Resource 
	WebServiceContext wsContext;

	@WebMethod(operationName = "putIndex", action = "urn:PutIndex")
	public Integer putIndex(@WebParam(name = "arg0") PeerWS peer, @WebParam(name = "arg1") String description) {
		Integer msjId = messagesCounter++;
		logger.info(msjId+"->putIndex - Recibo la descripcion del recurso del peer "+peer.toString());
		ResourceDescriptionWS resourceDesc = Deserializer.deserializeDescription(description);
		Integer result = IndexManager.getInstance().putDescription(peer, resourceDesc);
		logger.info(msjId+"<-putIndex - Retorno "+result+" a "+peer.toString());
		return result;
	}

	@WebMethod(operationName = "updateIndex", action = "urn:UpdateIndex")
	public Integer updateIndex(@WebParam(name = "arg0") PeerWS peer, @WebParam(name = "arg1") String description) {
		Integer msjId = messagesCounter++;
		logger.info(msjId+"->updateIndex - Recibo la actualizacion de la descripcion del recurso del peer "+peer.toString());
		ResourceDescriptionWS resourceDesc = Deserializer.deserializeDescription(description);
		Integer result =  IndexManager.getInstance().addSubDescription(peer,resourceDesc);
		logger.info(msjId+"<-updateIndex - Retorno "+result+" a "+peer.toString());
		return result;
	}

	@WebMethod(operationName = "query", action = "urn:Query")
	public ResultsWS query(@WebParam(name = "arg0") PeerWS peer, @WebParam(name = "arg1") String query) {
		Integer msjId = messagesCounter++;
		logger.info(msjId+"->query - Recibo consulta \""+query+"\" del peer "+peer.toString());
		CORI coriAlgorithm = new CORI();
		List<ResourceRank> resourcesRank = coriAlgorithm.rankResources(query);
		QueryPropagator propagator = new QueryPropagator( query,resourcesRank);
		List<QueryResultVO> results;
		try {
			results = propagator.propagateQuery();
		} catch (Exception e) {
			logger.error("Ocurrio un error intentando propagar la query \""+query+"\"", e);
			results = new ArrayList<QueryResultVO>();
		}
		ResultsWS returned = new ResultsWS();
		returned.setResults(results);
		logger.info(msjId+"<-query - Retorno respuesta de query \""+query+"\" al peer "+peer.toString()+returned.toString());
		return returned;
	}

	@WebMethod(operationName = "sayHello", action = "urn:SayHello")
	public Integer sayHello(@WebParam(name = "arg0") PeerWS peer) {
		Integer msjId = messagesCounter++;
		logger.info(msjId+"->sayHello - Se da de alta el peer "+peer.toString());
		MessageContext context = wsContext.getMessageContext();
		HttpServletRequest request = (HttpServletRequest) context.get(MessageContext.SERVLET_REQUEST);
		peer.setAddress(request.getRemoteAddr());
		Integer result;
		if (PeerManager.getInstance().hasPeer(peer)) {
			result =  PeerManager.getInstance().enablePeer(peer);
		} else {
			result =  PeerManager.getInstance().addPeer(peer);
		}
		logger.info(msjId+"<-sayHello - Retorno "+result+" al peer "+peer.toString());
		return result;
	}

	@WebMethod(operationName = "sayGoodbye", action = "urn:SayGoodbye")
	public Integer sayGoodbye(@WebParam(name = "arg0") PeerWS peer) {
		Integer msjId = messagesCounter++;
		logger.info(msjId+"->sayGoodbye - Se da de baja el peer "+peer.toString());
		Integer result = PeerManager.getInstance().disablePeer(peer);
		logger.info(msjId+"<-sayGoodbye - Retorno "+result+" al peer "+peer.toString());
		return result;
	}

}
